package cn.jnetty.utils.create.dto;

import cn.jnetty.utils.create.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;

/**
 * @author 猪哥亮
 * @email 1030681978@qq.com
 * @date 2020/4/20 11:57
 * 描述：
 */
public class JnettyDtoCreateBuild {
    private static final Logger LOGGER = LoggerFactory.getLogger(JnettyDtoCreateBuild.class);
    private static final String PACKAGE_INFO_CLASS = "package-info.class";
    private static final String CLASS_SUFFIX = ".class";

    public static void iocLoader(CreateEntity buildPath) {
        Set<CodeModel> set = new HashSet<>();
        JnettyResourceScanning.scanPackage(buildPath.getScanPackages(), (resource) -> analysisResource(resource, set, buildPath));
        reflectBean(set, buildPath);
    }

    private static void analysisResource(Resource resource, Set<CodeModel> set, CreateEntity buildPath) {
        String resourceName = resource.getName();

        // 忽略 package-info.class
        if (PACKAGE_INFO_CLASS.equals(resourceName)) {
            return;
        }

        // 忽略非Class文件
        if (!resourceName.endsWith(CLASS_SUFFIX)) {
            return;
        }
        Class<?> clazz = ClassUtils.loadClass(resourceName.substring(0, resourceName.length() - 6).replaceAll("[/\\\\]", "."));
        Annotation proco = clazz.getAnnotation(JnettyPrototobuf.class);
        if (proco instanceof JnettyPrototobuf) {
            JnettyPrototobuf p = JnettyPrototobuf.class.cast(proco);
            set.add(new CodeModel(buildPath.getCsDtoPath() + p.value(), "", clazz));
        }

    }

    /**
     * 反射对象
     *
     * @param
     */
    private static void reflectBean(Set<CodeModel> set, CreateEntity buildPath) {
        if (set.size() <= 0) {
            return;
        }
        Iterator<CodeModel> iterator = set.iterator();
        StringBuilder sb = new StringBuilder();
        sb.append("syntax = \"proto3\";\n")
                .append(buildPath.getImpots())
                .append("option java_package = \"")
                .append(buildPath.getJvDtoPacket())
                .append("\";\n")
                .append("option csharp_namespace = \"")
                .append(buildPath.getDtoName())
                .append("\";\n")
                .append("option java_outer_classname = \"")
                .append(buildPath.getDtoName())
                .append("\";\n");
        while (iterator.hasNext()) {
            Object o = null;
            try {
                CodeModel model = iterator.next();
                o = model.getClazz().getDeclaredConstructor().newInstance();
                List<String> bean1 = reflectField(model.getId(), o);
                sb.append(builder(bean1));
            } catch (Exception e) {
                LOGGER.error("", e);
            }
        }
        JnettyCreate.create(buildPath.getDtoName() + ".proto", sb.toString(), buildPath.getCsDtoPath());
        JnettyCreate.create(buildPath.getDtoName() + ".proto", sb.toString(), buildPath.getJvDtoPath());
    }

    private static List<String> reflectField(String id, Object o) {
        Field[] fields = o.getClass().getDeclaredFields();
        List<String> sb = new ArrayList<>();
        //便利获取父类（不包括Object）的属性
        Class c = o.getClass().getSuperclass();
        while (c != Object.class) {
            int srcLength = fields.length;
            Field[] superFields = c.getDeclaredFields();
            fields = Arrays.copyOf(fields, fields.length + superFields.length);
            System.arraycopy(superFields, 0, fields, srcLength, superFields.length);
            c = c.getSuperclass();
        }
        if (fields.length <= 0) {
            return null;
        }
        String beanName = o.getClass().getName();
        String clazz = "message " + o.getClass().getSimpleName() + " {\n";
        sb.add(clazz);
        for (int i = 0; i < fields.length; i++) {
            //忽略生成字段
            if (checkOverlook(fields[i])) {
                continue;
            }
            //属性名
            String field = fields[i].getName();
            String s = "\t" + TypeUtils.typeStr1(fields[i], beanName) + " " + field + " = " + (i + 1) + ";\n";
            sb.add(s);
        }
        sb.add("}\n");
        return sb;
    }

    private static String builder(List<String> s) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < s.size(); i++) {
            sb.append(s.get(i));
        }
        return sb.toString();
    }

    /**
     * 是否可以忽略生成该字段
     *
     * @return
     */
    private static boolean checkOverlook(Field f) {
        Annotation ann = f.getAnnotation(OverlookField.class);
        return (ann instanceof OverlookField);
    }

}
